/*
 * Copyright (c) 2011 Obix Labs Limited
 * Redistribution and use in source and binary forms, 
 * with or without modification, are permitted provided 
 * that the following conditions are met:
 * 
 * 		Redistribution of source code must retain the above 
 * 		copyright notice, this list of conditions and the 
 * 		following disclaimer.
 *
 * 		Redistribution in binary form must reproduce the 
 * 		above copyright notice, this list of conditions 
 * 		and the following disclaimer in the documentation 
 * 		and/or other materials provided with the distribution.
 * 
 * 	THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF 
 * 	ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS 
 * 	AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * 	FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, 
 * 	ARE HEREBY EXCLUDED. OBIX LABS LIMITED ("Obix Labs") AND ITS 
 * 	LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 
 * 	AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR 
 * 	ITS DERIVATIVES. IN NO EVENT WILL Obix Labs OR ITS LICENSORS BE 
 * 	LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, 
 * 	INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 
 * 	DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 
 * 	LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS 
 * 	SOFTWARE, EVEN IF Obix Labs HAS BEEN ADVISED OF THE POSSIBILITY OF 
 * 	SUCH DAMAGES.
 */

package com.obixlabs.commons.xml;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * <p>
 * An implementation of the {@link ErrorHandler} interface which 
 * collates errors and warnings reported during XML validation, so that 
 * they can be retrieved/formatted post validation.
 * </p>
 * <p>
 * <b>Note</b> that this handler will cause a {@link SAXException} to be thrown 
 * if a fatal error is detected during validation. All other errors and warnings
 * are simply collated during the validation process.
 * </p> 
 */
public class ObixXmlValidationErrorHandler implements ErrorHandler
{
	/**
	 * <p>
	 * A {@link Collection collection} which holds the errors that occur during the 
	 * validation process.
	 * </p>
	 */
	private ArrayList<SAXException> errors;
	
	/**
	 * <p>
	 * A {@link Collection collection} which holds the warnings issued during the 
	 * validation process.
	 * </p>
	 */		
	private ArrayList<SAXException> warnings;

	/**
	 * <p>
	 * Default constructor
	 * </p>
	 */
	public ObixXmlValidationErrorHandler()
	{
		errors=new ArrayList<SAXException>();
		warnings=new ArrayList<SAXException>();
	}

	@Override
	public void error(SAXParseException saxException) throws SAXException 
	{errors.add(saxException);}

	@Override
	public void fatalError(	SAXParseException saxParserException) throws SAXException 
	{
	        errors.add(saxParserException);
	        throw saxParserException;
	}
	
	@Override
	public void warning(	SAXParseException saxParserException)  throws SAXException 
	{warnings.add(saxParserException);}
	
	/**
	 * <p>
	 * Indicates if any errors occurred during validation.
	 * </p>
	 * <p><b>Note</b> That if the parser raised a fatal error, a {@link SAXException} would 
	 * have been thrown by this handler in order to trigger an abort the parsing process.
	 * </p>
	 * 
	 * @return <code>True</code> if the validating parser reported any errors, 
	 * and <code>False</code> otherwise.
	 */
	public boolean errorsOccured(){return !errors.isEmpty();}
	
	/**
	 * <p>
	 * Indicates if any warnings occurred during validation.
	 * </p>
	 * 
	 * @return <code>True</code> if the validating parser reported any warnings, 
	 * and <code>False</code> otherwise.
	 */
	public boolean warningsOccured(){return !warnings.isEmpty();}
		
	/**
	 * <p>
	 * Concatenates the {@link #warning(SAXParseException) warnings} and 
	 * {@link #error(SAXParseException) errors} issued by the validating parser 
	 * into a contiguous {@link String string}, delimited by new-line characters, 
	 * and with each entry preceded by a tab character.  
	 * </p>
	 * 
	 * @return A {@link String string} representation of the {@link #warning(SAXParseException) warnings} 
	 * and {@link #error(SAXParseException) errors} recorded during the validation process.
	 */			
	public String formatMessage()
	{
		StringBuffer result=new StringBuffer();
		
		result.append(formatWarnings());
		result.append(formatErrors());
		
		return result.toString();
	}
	
	/**
	 * <p>
	 * Concatenates the {@link #warning(SAXParseException) warnings} issued by the validating 
	 * parser into a contiguous {@link String string}, delimited by a new-line, 
	 * and also with each entry preceded by a tab character.
	 * </p>
	 * 
	 * @return A {@link String string} representation of the {@link #warning(SAXParseException) warnings} 
	 * recorded during the validation process.
	 */
	public String formatWarnings()
	{
		StringBuffer result=new StringBuffer();
		if (!warnings.isEmpty())
		{
			Iterator<SAXException> warningsIterator=warnings.iterator();
			SAXException saxWarning;
			result.append("Warnings:\n");
			int warningsIndex=1;
			while (warningsIterator.hasNext())
			{
				saxWarning=warningsIterator.next();
				result.append("\tWarning " + warningsIndex + ". " + 
									saxWarning.getMessage()+"\n");
				warningsIndex++;
			}
		}
		return result.toString();			
	}
	
	/**
	 * <p>
	 * Concatenates the errors issued by the validating parser into a contiguous
	 * {@link String string}, delimited by new-line characters, and with each entry is preceded by 
	 * a tab character.    
	 * </p>
	 * 
	 * @return A String representation of the errors recorded during the parsing 
	 * and validation process.
	 */		
	public String formatErrors()
	{
		StringBuffer result=new StringBuffer();
		if (!errors.isEmpty())
		{
			Iterator<SAXException> errorsIterator=errors.iterator();
			SAXException saxError;
			result.append("Error:\n");
			int index=1;
			while (errorsIterator.hasNext())
			{
				saxError=errorsIterator.next();
				result.append("\tError " + index + ". " + saxError.getMessage()+"\n");
				index++;
			}//end while
		}//end if
		return result.toString();			
	}	
}